#include "stdafx.h"
#include "transform/Transform.h"
#include "GameObject.h"
#include "config/Def.h"
#include "scene/Stage.h"
#include "component/Mesh.h"
#include "component/Material.h"
#include "component/ComponentHolder.h"

using namespace unigame;

GameObject::~GameObject()
{
	delete[] m_name;
	uni_delete(m_mesh);
	uni_delete(m_material);
	for(std::list<ComponentHolder*>::iterator it = m_componentList.begin(); it != m_componentList.end(); ++it)
	{
		delete *it;
	}
	m_componentList.clear();
}

GameObject::GameObject(const char* name):
Object(), 
AutoRelease(),
m_flag(0),
m_father(0),
m_firstChild(0),
m_sibling(0),
m_layer(1),
m_enable(true),
m_visible(true),
m_mesh(0),
m_material(0),
m_childNumber(0),
m_type(E_GAMEOBJECT_GOT)
{
	int32u len = strlen(name) + 1;
	m_name = uni_new char[len];
	memcpy(m_name, name, len);
	m_transform.init(this);
}

void GameObject::name(const char* name)
{
	if(name == m_name)
	{
		return;
	}
	if(m_name != 0)
	{
		delete[] m_name;
	}
	int32u len = strlen(name) + 1;
	m_name = uni_new char[len];
	memcpy(m_name, name, len);
}

GameObject* GameObject::operator [](const char* name)
{
	GameObject* go = m_firstChild;
	while(go && go != this)
	{
		if(strcmp(name, go->m_name) == 0)
		{
			return go;
		}
		go = go->next();
	}
	return 0;
}

Mesh* GameObject::mesh()
{
	if(m_mesh)
	{
		return (Mesh*)(m_mesh->value());
	}
	return 0;
}

Material* GameObject::material()
{
	if(m_material)
	{
		return (Material*)(m_material->value());
	}
	return 0;
}

void GameObject::enable()
{
	if(!m_enable)
	{
		m_enable = true;
		Stage::setFlag(E_RENDER_LIST_CHANGE_SF);
	}
}

void GameObject::disable()
{
	if(m_enable)
	{
		m_enable = false;
		Stage::setFlag(E_RENDER_LIST_CHANGE_SF);
	}
}

void GameObject::setVisiable(bool isVisible)
{
	if(m_visible != isVisible)
	{
		m_visible = isVisible;
		Stage::setFlag(E_RENDER_LIST_CHANGE_SF);
	}
}

void GameObject::addComponent(Component* com)
{
	ComponentHolder* ch = uni_new ComponentHolder(com, this);
	m_componentList.push_back(ch);
}

ComponentHolder* GameObject::getComponent(int32u type)
{
	for(std::list<ComponentHolder*>::iterator it = m_componentList.begin(); it != m_componentList.end(); ++it)
	{
		if((*it)->type() == type)
		{
			return *it;
		}
	}
	return 0;
}

Component* GameObject::removeComponent(int32u type)
{
	for(std::list<ComponentHolder*>::iterator it = m_componentList.begin(); it != m_componentList.end(); ++it)
	{
		if((*it)->type() == type)
		{
			m_componentList.erase(it);
			Component* com = (*it)->value();
			delete *it;
			return com;
		}
	}
	return 0;
}

GameObject* GameObject::next(bool hasChecked)
{
	if(!hasChecked && m_firstChild)
	{
		return m_firstChild;
	}
	if(m_sibling)
	{
		return m_sibling;
	}
	if(!m_father)
	{
		return 0;
	}
	return m_father->next(true);
}

void GameObject::addChild(GameObject* obj)
{
	if(obj == 0)
	{
		return;
	}
	++m_childNumber;
	obj->removeFromFather();
	obj->m_sibling = m_firstChild;
	m_firstChild = obj;
	obj->onAddToFather(this);
}

void GameObject::mesh(Mesh* mesh)
{
	if(m_mesh)
	{
		m_mesh->value(mesh);
	}
	else
	{
		m_mesh = uni_new ComponentHolder(mesh, this);
	}
	Stage::setFlag(E_RENDER_LIST_CHANGE_SF);
}

void GameObject::material(Material* mat)
{
	if(m_material)
	{
		m_material->value(mat);
	}
	else
	{
		m_material = uni_new ComponentHolder(mat, this);
	}
	Stage::setFlag(E_RENDER_ORDER_CHANGE_SF);
}

void GameObject::onRemoveFromFather(GameObject* father)
{
	this->m_father = 0;
	m_transform.onRemoveFromFather(father);
	if(father)
	{
		this->release();
	}
	Stage::setFlag(E_RENDER_LIST_CHANGE_SF);
}

void GameObject::release()
{
	AutoRelease::release();
	if(m_referenceCount <= 0)
	{
		GameObject* go = this->next();
		while(go && go != this)
		{
			go->releaseGameObject();
			go = go->next();
		}
	}
}

void GameObject::onAddToFather(GameObject* father)
{
	this->m_father = father;
	m_transform.onAddToFather();
	this->retain();
	Stage::setFlag(E_RENDER_LIST_CHANGE_SF);
}

void GameObject::removeFromFather()
{
	if(m_father == 0)
	{
		onRemoveFromFather(0);
	}
	else
	{
		m_father->removeChild(this);
	}
}

void GameObject::removeChild(GameObject* obj)
{
	GameObject* go = m_firstChild;
	GameObject* lastSibling = 0;
	while(go)
	{
		if(go == obj)
		{
			if(lastSibling)
			{
				lastSibling->m_sibling = go->m_sibling;
			}
			else
			{
				m_firstChild = go->m_sibling;
			}
			go->m_sibling = 0;
			go->onRemoveFromFather(this);
			--m_childNumber;
			break;
		}
		lastSibling = go;
		go = go->m_sibling;
	}
}

void GameObject::update()
{
	m_transform.update();
	for(std::list<ComponentHolder*>::iterator it = m_componentList.begin(); it != m_componentList.end(); ++it)
	{
		(*it)->value()->update();
	}
	if(m_transform.dirtyFlag() != 0)
	{
		setFlag(E_TRANSFORM_CHANGE_GOF);
	}
	else
	{
		clearFlag(E_TRANSFORM_CHANGE_GOF);
	}
	m_transform.resetFlag();
}
